package xorm_db

import (
	"strings"
	"xorm.io/builder"
	"xorm.io/xorm"
)

/*
基于xorm简单封装的数据库操作
IModel的方法中的entity和entityList需要实现TableName() string 方法
*/

// IModel Model接口
type IModel interface {
	// GetBaseModel 获取基础Model
	GetBaseModel() IModel
	// GetSession 获取数据库Session
	GetSession() *xorm.Session
	// SetSession 设置数据库Session
	SetSession(session *xorm.Session) IModel
	// IsAutoClose 是否自动关闭Session
	IsAutoClose(isAutoClose bool) IModel

	// InsertOne 插入一条记录
	InsertOne(entity interface{}) error
	// InsertBatch 批量插入记录
	InsertBatch(entityList ...interface{}) (int64, error)
	// Update 更新记录
	Update(entity interface{}, cond builder.Cond, cols ...string) (int64, error)
	// GetOne 获取一条记录并绑定到 entity
	GetOne(entity interface{}, cond builder.Cond, cols ...string) (bool, error)
	// GetList 获取多条记录并绑定到 entityList
	GetList(entityList interface{}, cond builder.Cond, page IPage, orderBy, groupBy string, cols ...string) (int64, error)
	// Rows 流式读取记录
	Rows(entity interface{}, cond builder.Cond) (*xorm.Rows, error)
}

// BaseModel Model接口默认实现
type BaseModel struct {
	session     *xorm.Session
	isAutoClose bool
}

// GetBaseModel 获取基础Model
func (m *BaseModel) GetBaseModel() IModel {
	return m
}

// GetSession 获取数据库Session
func (m *BaseModel) GetSession() *xorm.Session {
	return m.session
}

// SetSession 设置数据库Session
func (m *BaseModel) SetSession(session *xorm.Session) IModel {
	if nil != session {
		m.session = session
		m.isAutoClose = false
	}

	if nil == m.session {
		m.session = stdEngine.NewSession()
		m.isAutoClose = true
	}

	return m
}

// IsAutoClose 是否自动关闭Session
func (m *BaseModel) IsAutoClose(isAutoClose bool) IModel {
	m.isAutoClose = isAutoClose
	return m
}

// InsertOne 插入一条记录
func (m *BaseModel) InsertOne(entity interface{}) error {
	defer m.autoClose()
	m.SetSession(nil)

	_, err := m.session.InsertOne(entity)

	return err
}

// InsertBatch 批量插入记录
func (m *BaseModel) InsertBatch(entityList ...interface{}) (int64, error) {
	defer m.autoClose()
	m.SetSession(nil)

	return m.session.Insert(entityList...)
}

// Update 更新记录
func (m *BaseModel) Update(entity interface{}, cond builder.Cond, cols ...string) (int64, error) {
	defer m.autoClose()
	m.SetSession(nil)

	return m.session.Cols(cols...).Where(cond).Update(entity)
}

// GetOne 获取一条记录并绑定到 entity
func (m *BaseModel) GetOne(bean interface{}, cond builder.Cond, cols ...string) (bool, error) {
	defer m.autoClose()
	m.SetSession(nil)

	return m.session.Select(strings.Join(cols, ",")).Where(cond).Get(bean)
}

// GetList 获取多条记录并绑定到 entityList, page 不为nil时按分页查询
func (m *BaseModel) GetList(entityList interface{}, cond builder.Cond, page IPage, orderBy, groupBy string, cols ...string) (int64, error) {
	defer m.autoClose()
	m.SetSession(nil)

	m.session.Select(strings.Join(cols, ",")).Where(cond)
	if nil != page && 0 < page.GetLimit() {
		m.session.Limit(page.GetLimit(), page.GetOffset())
	}

	if "" != orderBy {
		m.session.OrderBy(orderBy)
	}

	if "" != groupBy {
		m.session.GroupBy(groupBy)
	}

	return m.session.FindAndCount(entityList)
}

// Rows 流式读取记录
func (m *BaseModel) Rows(entity interface{}, cond builder.Cond) (*xorm.Rows, error) {
	defer m.autoClose()
	m.SetSession(nil)

	return m.session.Where(cond).Rows(entity)
}

// autoClose 开启自动关闭时关闭Session
func (m *BaseModel) autoClose() {
	if false == m.isAutoClose {
		return
	}

	if err := m.session.Close(); nil != err {
		panic(err)
	}
}

// NewBaseModel 获取新的BaseModel实例
func NewBaseModel(session *xorm.Session) *BaseModel {
	model := &BaseModel{}
	model.SetSession(session)

	return model
}
